﻿using System.Collections.Generic;
using System.Collections;
using System.Text;

namespace JSON
{
    public interface IJSONObject
    {
        JSONCollection WriteObject();
    }

    public abstract class JSONElement
    {
        protected string m_Name;
        protected JSONElement() { }
        public abstract string Print();

        protected string m_Separ = " : ";
        protected string m_Quote = "\"";

        public string ToJSONSTring(string obj)
        {
            if (string.IsNullOrEmpty(obj))
                return "";
            else
                return obj.Replace('\"', '\'');
        }
    }

    public class JSONNumber<T> : JSONElement where T : struct
    {
        T m_Value;

        public JSONNumber(string Name, T Value)
        {
            m_Name = Name;
            m_Value = Value;
        }
        public override string Print()
        {
            return m_Quote + m_Name + m_Quote +
                   m_Separ +
                   this.ToJSONSTring(m_Value.ToString());
        }
    }

    public class JSONString : JSONElement
    {
        string m_Value;

        public JSONString(string Name, string Value)
        {
            m_Name = Name;
            m_Value = Value;
        }
        public override string Print()
        {
            return m_Quote + m_Name + m_Quote +
                  m_Separ +
                  m_Quote + this.ToJSONSTring(m_Value) + m_Quote;
        }
    }

    public class JSONBoolean : JSONElement
    {
        bool m_Value;

        public JSONBoolean(string Name, bool Value)
        {
            m_Name = Name;
            m_Value = Value;
        }
        public override string Print()
        {
            return m_Quote + m_Name + m_Quote +
                   m_Separ +
                   this.ToJSONSTring(m_Value.ToString().ToLower());
        }
    }

    public class JSONCollection : JSONElement
    {
        protected List<JSONElement> m_Value;
        protected string m_BraceOpen;
        protected string m_BraceClose;

        protected bool m_omitName;

        public JSONCollection(string Name, params JSONElement[] Value)
            : this(Name, (IEnumerable)Value)
        { }

        public bool OmitName
        {
            get { return m_omitName; }
            set { m_omitName = value; }
        }

        public JSONCollection(string Name, IEnumerable Value)
        {
            m_Name = Name;
            m_Value = new List<JSONElement>();

            IEnumerator myEnumerator = Value.GetEnumerator();

            while (myEnumerator.MoveNext())
            {
                if (myEnumerator.Current is JSONElement)
                {
                    if (this is JSONArray && myEnumerator.Current is JSONObject)
                    {
                        JSONObject j = myEnumerator.Current as JSONObject;
                        j.OmitName = true;

                    }
                    m_Value.Add(myEnumerator.Current as JSONElement);
                }
            }
        }
        public override string Print()
        {
            StringBuilder s = new StringBuilder();



            if (this.OmitName)
            {
            }
            else
            {
                s.AppendLine(m_Quote + m_Name + m_Quote + m_Separ);
            }



            s.AppendLine(m_BraceOpen);
            for (int i = 0; i < m_Value.Count; i++)
            {

                s.Append(m_Value[i].Print());

                if (i != m_Value.Count - 1)
                {
                    s.Append(",");
                }
                s.AppendLine();
            }

            s.AppendLine(m_BraceClose);

            return s.ToString();
        }
    }

    public class JSONArray : JSONCollection
    {

        public JSONArray(string Name, params JSONElement[] Value)
            : this(Name, (IEnumerable)Value)
        {

        }
        public JSONArray(string Name, IEnumerable Value)
            : base(Name, Value)
        {
            m_BraceOpen = "[";
            m_BraceClose = "]";
        }

    }

    public class JSONObject : JSONCollection
    {



        public JSONObject(string Name, params JSONElement[] Value)
            : this(Name, (IEnumerable)Value)
        {

        }
        public JSONObject(string Name, IEnumerable Value)
            : base(Name, Value)
        {
            m_omitName = false;
            m_BraceOpen = "{";
            m_BraceClose = "}";
        }
        public string Print(bool rootElement)
        {
            this.OmitName = true;
            return base.Print();
        }
    }
}